/* derive_p12_pass.c
 * 
 * 用来从口令 + salt 文件推导出 PKCS#12 的真实密码（hex 格式）。
 *
 * 编译：
 *   gcc -o derive_p12_pass derive_p12_pass.c -lcrypto
 *
 * 用法：
 *   ./derive_p12_pass <salt_file> <password>
 *
 * 示例：
 *   ./derive_p12_pass /etc/pki/audit/p12_salt 123456
 */

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <openssl/evp.h>
#include <openssl/err.h>

#define SALT_BYTES 16
#define DERIVE_BYTES 32
#define DERIVE_ITERATIONS 200000  /* 和 audit-keygen 保持一致 */

static int hex2bin(const char *hex, unsigned char *out, size_t outlen) {
    size_t len = strlen(hex);
    if (len % 2 != 0 || len / 2 > outlen) return -1;
    for (size_t i = 0; i < len / 2; i++) {
        unsigned int byte;
        if (sscanf(hex + 2*i, "%2x", &byte) != 1) return -1;
        out[i] = (unsigned char)byte;
    }
    return len / 2;
}

static void bin2hex(const unsigned char *in, size_t len, char *out, size_t outlen) {
    static const char hex[] = "0123456789abcdef";
    if (outlen < len*2+1) return;
    for (size_t i=0;i<len;i++) {
        out[i*2]   = hex[(in[i] >> 4) & 0xF];
        out[i*2+1] = hex[in[i] & 0xF];
    }
    out[len*2] = '\0';
}

int main(int argc, char **argv) {
    if (argc != 3) {
        fprintf(stderr, "用法: %s <salt_file> <password>\n", argv[0]);
        return 1;
    }

    const char *salt_file = argv[1];
    const char *password = argv[2];

    /* 读取 salt（hex 格式） */
    FILE *f = fopen(salt_file, "r");
    if (!f) { perror("fopen salt"); return 1; }
    char hexbuf[128];
    if (!fgets(hexbuf, sizeof(hexbuf), f)) { perror("fgets salt"); fclose(f); return 1; }
    fclose(f);

    size_t len = strlen(hexbuf);
    while (len && (hexbuf[len-1]=='\n' || hexbuf[len-1]=='\r')) hexbuf[--len] = 0;

    unsigned char salt[SALT_BYTES];
    if (hex2bin(hexbuf, salt, sizeof(salt)) != SALT_BYTES) {
        fprintf(stderr, "salt 文件格式错误\n");
        return 1;
    }

    unsigned char derived[DERIVE_BYTES];
    const EVP_MD *md = EVP_get_digestbyname("sm3");
    if (!md) {
        fprintf(stderr, "[WARN] OpenSSL 无 sm3，使用 sha256\n");
        md = EVP_sha256();
    }

    if (!PKCS5_PBKDF2_HMAC(password, strlen(password), salt, sizeof(salt),
                           DERIVE_ITERATIONS, md, sizeof(derived), derived)) {
        fprintf(stderr, "PBKDF2 失败\n");
        return 1;
    }

    char passhex[DERIVE_BYTES*2+1];
    bin2hex(derived, sizeof(derived), passhex, sizeof(passhex));

    printf("真实 P12 密码: %s\n", passhex);
    return 0;
}
